
	/**
	 * @author senxation
	 * @name Pagination.js
	 */
	nhn.Pagination = new $Class({
		/** @lends nhn.Pagination */
		
		/**
		 * 리스트에 페이지 목록 매기고 페이지에 따른 네비게이션을 구현한 컴포넌트.
		 * 기본 목록은 마크업에 static하게 정의되어있고, 페이지 이동을위해 클릭시마다 보여줄 아이템 목록을 Ajax Call을 통해 받아온다.
		 * 페이지 컴포넌트가 로드되면 .loaded 클래스명이 추가된다.
		 * @constructs
		 * @param {String | HTMLElement} sId 페이지목록을 생성할 엘리먼트 id 혹은 엘리먼트 자체
		 * @param {Object} oOption 옵션 객체
		 * @example 
	var oPagination = new nhn.Pagination("paginate", {
		item : 1000, //전체 아이템 개수
		itemPerPage : 10, //한 페이지에 표시될 아이템 개수
		pagePerPageList : 10, //페이지목록에 표시될 페이지 개수
		page : 1, //초기 페이지
		moveUnit : "pagelist", //페이지목록 이동시 이동 단위 "page" || "pagelist"
		alignCenter : false //현재페이지가 항상 가운데 위치하도록 정렬. moveUnit이 "page"일 때만 사용
	}).attach({
		click : function(e) {
			//페이지 이동을 위해 클릭했을때 발생
			//전달되는 이벤트 객체 e = {
			//	page : (Number) 클릭된 페이지
			//}
			//e.stop()을 수행하면 페이지 이동(loaded 이벤트)이 일어나지 않는다.
		},
		loaded : function(e) {
			//페이지 이동이 완료된 이후 발생
			//전달되는 이벤트 객체 e = {
			//	page : (Number) 현재 페이지
			//}
		}
	});
		 */
		$init : function(sId, oOption){
			this._elPageList = $(sId);
			this._elCurrentPage = $("<strong>");
			this._elPage = $("<a>");
			$Element(this._elPage).attr("href","#");
			
			this._elAPrevEndPage = cssquery.getSingle("a.pre_end", this._elPageList);
			this._elAPrevPage = cssquery.getSingle("a.pre", this._elPageList);
			this._elANextEndPage = cssquery.getSingle("a.next_end", this._elPageList);
			this._elANextPage = cssquery.getSingle("a.next", this._elPageList);
			this._elSpanPrevEndPage = cssquery.getSingle("span.pre_end", this._elPageList);
			this._elSpanPrevPage = cssquery.getSingle("span.pre", this._elPageList);
			this._elSpanNextEndPage = cssquery.getSingle("span.next_end", this._elPageList);
			this._elSpanNextPage = cssquery.getSingle("span.next", this._elPageList);
			
			this._fClickPage = $Fn(this._onClickPageList, this);
			this._fClickPage.attach(this._elPageList, "click");
			
			this.option({
				item : 10,
				itemPerPage : 10,
				pagePerPageList : 10,
				page : 1,
				moveUnit : "pagelist",
				alignCenter : false
			});
			if (oOption) this.option(oOption);
			
			this.setItemCount(this.option("item"));
			this.movePageTo(this.option("page"));
			
			$Element(this._elPageList).addClass("loaded");
		},
		/**
		 * 전체 아이템의 개수를 리턴한다.
		 * @return {Number} 아이템 개수
		 */
		getItemCount : function() {
			return this.option("item");
		},
		
		/**
		 * 전체 아이템의 개수를 설정한다.
		 * @param {Number} n 아이템 개수
		 */
		setItemCount : function(n) {
			this.option({"item" : n});
		},
		
		/**
		 * 한 페이지에 보여줄 아이템의 개수를 구한다.
		 * @return {Number} 한 페이지에 보여줄 아이템의 개수
		 */
		getItemPerPage : function() {
			return this.option("itemPerPage");
		},
		
		/**
		 * 한 페이지에 보여줄 아이템의 개수를 설정한다.
		 * @param {Object} n 아이템 개수
		 */
		setItemPerPage : function(n) {
			this.option("itemPerPage", n);
		},
		
		/**
		 * 현재 페이지를 리턴한다.
		 * @return {Number} 현재 페이지
		 */
		getCurrentPage : function() {
			return this._nCurrentPage;
		},
		
		_getLastPage : function() {
			return Math.ceil(this.getItemCount() / this.getItemPerPage());
		},

		_getRelativePage : function(sRelative) {
			var nPage = null;

			if (this.option("moveUnit") == "page") {
				switch (sRelative) {
					case "pre" :
						nPage = this.getCurrentPage() - 1;
					break;
					case "next" :
						nPage = this.getCurrentPage() + 1;
					break;
				}
			}
			else {
				var nThisPageList = this._getPageList(this.getCurrentPage());
				switch (sRelative) {
					case "pre_end" :
						var nLastPageOfPrePageList = (nThisPageList - 1) * this.option("pagePerPageList");
						nPage = 1;
					break;
					case "pre" :
						var nLastPageOfPrePageList = (nThisPageList - 1) * this.option("pagePerPageList");
						nPage = nLastPageOfPrePageList;
					break;
					case "next" :
						var nFirstPageOfNextPageList = (nThisPageList) * this.option("pagePerPageList") + 1;
						nPage = nFirstPageOfNextPageList;
					break;
					case "next_end" :
						nPage = this._getLastPage();
					break;
				}
			}
			
			return nPage;
		},
		
		/**
		 * 몇번째 페이지 리스트인지 구함
		 * @param {Number} nThisPage
		 */
		_getPageList : function(nThisPage) {
			if (this.option("alignCenter")) {
				var nLeft = Math.floor(this.option("pagePerPageList") / 2);
				var nPageList = nThisPage - nLeft;
				if (nPageList < 1) nPageList = 1;
				if (nPageList > this._getLastPage()) nPageList = this._getLastPage();
				return nPageList;
			}
			return Math.ceil(nThisPage / this.option("pagePerPageList"));
		},
		
		_onClickPageList : function(e) {
			e.stop($Event.CANCEL_DEFAULT);
			
			var nPage = null;
			
			var el = e.element;
			if (el.tagName != "A") {
				el = cssquery.getSingle("! a", el);
				if (!el) return;
			}
			
			var we = $Element(el);
			if (we.hasClass("pre_end") || we.hasClass("pre") || we.hasClass("next") || we.hasClass("next_end")) {
				if (we.hasClass("pre_end")) {
					nPage = this._getRelativePage("pre_end");
				}
				else if (we.hasClass("pre")) {
					nPage = this._getRelativePage("pre");
				}
				else if (we.hasClass("next")) {
					nPage = this._getRelativePage("next");
				}
				else if (we.hasClass("next_end")) {
					nPage = this._getRelativePage("next_end");				
				}
			}
			else {
				var nPage = parseInt($Element(el).text());
			}
			
			if (!this.fireEvent("click", {element:el, page:nPage})) return;
			this.movePageTo(nPage);
		},
		
		/**
		 * 지정한 페이지로 이동하고 페이지 목록을 다시 그린다.
		 * 아이템 개수가 하나도 없으면 .no-result 페이지 목록이 하나밖에 없으면 .only-one 클래스명이 추가된다.  
		 * @param {Number} nPage 이동할 페이지 
		 */
		movePageTo : function(nPage){
			this._empty();

			var nLastPage = this._getLastPage();
			
			if (nLastPage == 0) {
				$Element(this._elPageList).addClass("no-result");
			}
			else if (nLastPage == 1) {
				$Element(this._elPageList).addClass("only-one");
			}
			else {
				$Element(this._elPageList).removeClass("only-one").removeClass("no-result");
			} 
			
			if (nPage < 1) nPage = 1;
			if (nPage > nLastPage) nPage = nLastPage;

			this._nCurrentPage = nPage;
			this._paginate(nPage);
			this.fireEvent("loaded",{page:nPage});
		},
		
		/**
		 * 페이징을 다시 그린다.
		 * @param {Number} nItemCount 아이템의 개수가 바뀌었을 경우 설정해준다.
		 */
		reset : function(nItemCount) {
			if (typeof nItemCount == "undefined") var nItemCount = this.option("item");
			else var nItemCount = nItemCount;
			
			this.setItemCount(nItemCount);
			this.movePageTo(1);
		},
		
		_paginate : function(nPage){
			this._empty();
			var nLastPage = this._getLastPage();
			var nThisPageList = this._getPageList(nPage);
			var nLastPageList = this._getPageList(nLastPage);
			
			if (this.option("alignCenter")) {
				var nLeft = Math.floor(this.option("pagePerPageList") / 2);
				var nFirstPageOfThisPageList = nPage - nLeft;
				if (nFirstPageOfThisPageList < 1) {
					nFirstPageOfThisPageList = 1;
				}
				var nLastPageOfThisPageList = nFirstPageOfThisPageList + this.option("pagePerPageList") - 1;
				if (nLastPageOfThisPageList > nLastPage) {
					nFirstPageOfThisPageList = nLastPage - this.option("pagePerPageList") + 1;
					if (nFirstPageOfThisPageList < 1) {
						nFirstPageOfThisPageList = 1;
					}
					nLastPageOfThisPageList = nLastPage;
				}
			}
			else {
				var nFirstPageOfThisPageList = (nThisPageList - 1) * this.option("pagePerPageList") + 1;
				var nLastPageOfThisPageList = (nThisPageList) * this.option("pagePerPageList");
				if (nLastPageOfThisPageList > nLastPage) nLastPageOfThisPageList = nLastPage;
			}
			

			if ((nThisPageList > 1) || (this.option("moveUnit") == "page" && nPage > 1)) {
				if (this._elAPrevEndPage) $Element(this._elPageList).append(this._elAPrevEndPage);
				$Element(this._elPageList).append(this._elAPrevPage);
			}
			else {
				if (this._elSpanPrevEndPage) $Element(this._elPageList).append(this._elSpanPrevEndPage);
				if (this._elSpanPrevPage) $Element(this._elPageList).append(this._elSpanPrevPage);	
			}		

			this._elPageList.appendChild(document.createTextNode("\n"));
			for (var i = nFirstPageOfThisPageList; i <= nLastPageOfThisPageList ; i++) {
				if (i == nPage) {
					var el = this._elCurrentPage.cloneNode(true);
				}
				else {
					var el = this._elPage.cloneNode(true);
				}
				if (i == nFirstPageOfThisPageList) {
					$Element(el).addClass("first-child");
				}
				$Element(el).text(i.toString());
				$Element(this._elPageList).append(el);
				
				this._elPageList.appendChild(document.createTextNode("\n"));
			}

			if ((nThisPageList < nLastPageList) || (this.option("moveUnit") == "page" && nPage < nLastPage)) {
				$Element(this._elPageList).append(this._elANextPage);
				if (this._elANextEndPage) $Element(this._elPageList).append(this._elANextEndPage);	
			}
			else {
				if (this._elSpanNextPage) $Element(this._elPageList).append(this._elSpanNextPage);
				if (this._elSpanNextEndPage) $Element(this._elPageList).append(this._elSpanNextEndPage);
			}
		},
		
		_empty : function(){
			if (this._elAPrevEndPage) this._elAPrevEndPage = this._elAPrevEndPage.cloneNode(true); 
			if (this._elAPrevPage) this._elAPrevPage = this._elAPrevPage.cloneNode(true); 
			if (this._elANextEndPage) this._elANextEndPage = this._elANextEndPage.cloneNode(true);
			if (this._elANextPage) this._elANextPage = this._elANextPage.cloneNode(true);
			if (this._elSpanPrevEndPage) this._elSpanPrevEndPage = this._elSpanPrevEndPage.cloneNode(true);
			if (this._elSpanPrevPage) this._elSpanPrevPage = this._elSpanPrevPage.cloneNode(true);
			if (this._elSpanNextEndPage) this._elSpanNextEndPage = this._elSpanNextEndPage.cloneNode(true);
			if (this._elSpanNextPage) this._elSpanNextPage = this._elSpanNextPage.cloneNode(true);
			$Element(this._elPageList).empty();
		}
	}).extend(nhn.Component);
